Repository navigation
fix(codegen-spring): make ejected generators compile when ejected alone - #430
Merged
Merged
Conversation
…ed alone An ejected Java routes, dto or value-object copy called static helpers on the packaged SpringDtoGenerator and SpringRepositoryGenerator with no import, and eject rewrote only the package line, so each failed to compile on its own (12, 3 and 3 errors). The shared emit rules now sit in one public SpringGeneratorSupport that every ejectable Spring generator imports, and eject copies it beside the owned generators, once, honouring -Dforce, with -Dlist and metaobjects:verify treating it like an owned runtime file. No packaged class an owned generator reaches refers to it. The four 1.0.x AutoSetSupport selectors stay as deprecated, self-contained methods. In Python, emits_router and has_literal_default moved to a shared predicates module that metaobjects eject copies through the runtime mechanism. Tests eject each registered generator alone in Java and Kotlin, and import each Python generator in a fresh interpreter. Generated output is unchanged.
…Kotlin helpers removed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
SpringGeneratorSupportthat every ejectable Spring generator imports.metaobjects:ejectcopies it as an owned file beside the ejected generators, soroutes,dtoandvalue-objectcompile when ejected alone. Generated output is unchanged.-Dlistandmetaobjects:verifytreat the copy like other owned runtime files.AutoSetSupportselectors from 1.0.x (stampFields,onUpdateFields,hasAutoSetFields,hasOnUpdateFields) are restored as@Deprecatedand self-contained. The 1.1.0 upgrade notes add a Java re-eject step.filter-allowlistandextractorno longer import helpers from sibling generators. The shared predicates ship asshared_predicatesthrough theruntime=eject mechanism.KotlinEntityGenerator.ktandKotlinM2mSupport.kt, the two Kotlin files this PR touches, between v1.0.13 and this head. No published helper was removed or changed signature, so no Kotlin forwarder is needed. The edits are two comment references.Fixedentry, the own-your-codegen feature doc, and the Java and Kotlin port notes.Validation runs on this branch: 2.
Validation
Risk Assessment
✅ Low: The helper move is a body-for-body relocation with every 1.0.13 public and protected signature restored as a forwarder, the eject, list and verify paths trace correctly for first eject, later eject and forced re-eject, the Python gate change in render_router is equivalent to the old chain, and the only finding is a test-coverage gap with no current defect; no tests were run in this review.
Testing
Baseline ts-fast/ts-unit already green. Drove the eject path through its real entry points: Java
MetaDataEjectMojoin-process viaEjectAloneRoundTripTest(6 tests: every registry generator ejected alone and javac-compiled with packaged support hidden; byte-identical output; owned-edit propagation). KotlinEjectedGeneratorAloneCompilesTestpassed. SpringAutoSetSupportLegacyFormsTest,SpringGeneratorLegacyFormsTest,SpringDtoGeneratorExtensibilityTestandOwnedPathNeverReachesPackagedSupportTestpassed. Pythontest_eject_independence.pyandtest_eject_runtime.pypassed (13 passed; 2 runtime route tests skipped, fastapi missing). Regression: full Python suite minustests/integrationpassed (2829 passed, 2 skipped); fullmvn -o testfor maven-plugin and codegen-spring passed. Untested:tests/integration(needs fastapi and pg8000, not in offline cache). Cleaned uv.lock edits, .venv and target dirs. No dollar spend; subscription quota only.Pipeline
Updates from git push no-mistakes
✅ **Intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
CHANGELOG.md:63- The 1.1.0 upgrade bullet "An ejected Java Spring generator needs a re-eject" (CHANGELOG.md:63-68) states that a copy ofroutes,dto,repositoryorvalue-objectmade before 1.1.0 "calls static helpers on the packagedSpringDtoGeneratorandSpringRepositoryGenerator... so it stops compiling after the upgrade". The source does not support that. A v1.0.13 copy has no import of either sibling (v1.0.13 SpringControllerGenerator.java:7-11, SpringDtoGenerator.java:7-12, SpringValueObjectGenerator.java:7-9), soSpringDtoGenerator.x(...)in an owned copy resolves only to the owned sibling in the same package, never to the packaged class. Concrete case: the trioroutes,dto,repositoryejected together on 8.0.13 (the one combination that compiled) calls its ownSpringDtoGenerator/SpringRepositoryGenerator, and its only calls into a packaged class this change touched are the fourAutoSetSupportselectors (v1.0.13 controller :324,:373,:1026,:1076; dto :220,:244,:268,:521), which this change restores as@Deprecated. That trio still compiles on 8.1.0.repositoryalone calls neither class. The bullet also contradicts the same file at CHANGELOG.md:883-886 ("still there, marked@Deprecated, so code that calls them still compiles"), the comment at AutoSetSupport.java:91-97, the javadoc of AutoSetSupportLegacyFormsTest, and the recorded round 3 decision ("Add the Java step to the 1.1.0 upgrade notes: old owned copies keep compiling; re-eject with -Dforce=true to own the rules"). The only copy that does stop compiling is one the adopter repaired by hand with an import of the packagedSpringDtoGeneratororSpringRepositoryGenerator(for exampledtoalone plus an import forappliesTo). Fix: reword the bullet to say that copies ejected before 1.1.0 keep compiling and keep applying the 1.0.x rules; re-eject with-Dforce=trueto own the shared rules inSpringGeneratorSupport; a copy edited to import the packagedSpringDtoGeneratororSpringRepositoryGeneratormust be re-ejected, because those helpers moved. Keep thegit diffmerge advice. No other file repeats the wrong claim.🔧 Fix applied.
2 warnings still open:
CHANGELOG.md:63- The 1.1.0 upgrade bullet "An ejected Java Spring generator needs a re-eject" (CHANGELOG.md:63-68) states that a copy ofroutes,dto,repositoryorvalue-objectmade before 1.1.0 "calls static helpers on the packagedSpringDtoGeneratorandSpringRepositoryGenerator... so it stops compiling after the upgrade". The source does not support that. A v1.0.13 copy has no import of either sibling (v1.0.13 SpringControllerGenerator.java:7-11, SpringDtoGenerator.java:7-12, SpringValueObjectGenerator.java:7-9), soSpringDtoGenerator.x(...)in an owned copy resolves only to the owned sibling in the same package, never to the packaged class. Concrete case: the trioroutes,dto,repositoryejected together on 8.0.13 (the one combination that compiled) calls its ownSpringDtoGenerator/SpringRepositoryGenerator, and its only calls into a packaged class this change touched are the fourAutoSetSupportselectors (v1.0.13 controller :324,:373,:1026,:1076; dto :220,:244,:268,:521), which this change restores as@Deprecated. That trio still compiles on 8.1.0.repositoryalone calls neither class. The bullet also contradicts the same file at CHANGELOG.md:883-886 ("still there, marked@Deprecated, so code that calls them still compiles"), the comment at AutoSetSupport.java:91-97, the javadoc of AutoSetSupportLegacyFormsTest, and the recorded round 3 decision ("Add the Java step to the 1.1.0 upgrade notes: old owned copies keep compiling; re-eject with -Dforce=true to own the rules"). The only copy that does stop compiling is one the adopter repaired by hand with an import of the packagedSpringDtoGeneratororSpringRepositoryGenerator(for exampledtoalone plus an import forappliesTo). Fix: reword the bullet to say that copies ejected before 1.1.0 keep compiling and keep applying the 1.0.x rules; re-eject with-Dforce=trueto own the shared rules inSpringGeneratorSupport; a copy edited to import the packagedSpringDtoGeneratororSpringRepositoryGeneratormust be re-ejected, because those helpers moved. Keep thegit diffmerge advice. No other file repeats the wrong claim.CHANGELOG.md:888- The change removes published static helpers from two packaged generator classes in a minor release, and only the fourAutoSetSupportselectors got a compatibility shim. Removed since v1.0.13: onSpringDtoGenerator, publicsettableFields(MetaObject, String),scalarFields,dtoComponentFields,valueObjectJsonbFields,valueObjectMapFields,isValueObjectJsonbField,componentType,isRequired,originGuaranteedNonNull,validationAnnotations, and protectedsizeAnnotation,attrBool,attrInt,hasValidator,escapeJavaString; onSpringRepositoryGenerator, publicappliesTo,m2mFinderName,m2mFinderNameForSubtype,targetSubtypeParam. Concrete sequence: an adopter on 8.0.13 subclassesSpringDtoGenerator(the extension contractSpringDtoGeneratorExtensibilityTestpins) and calls the inheritedvalidationAnnotations(field)orcomponentType(field, owner), or their own generator callsSpringDtoGenerator.dtoComponentFields(entity)asJavaFieldShapesdid. After upgrading to 8.1.0 that code fails withcannot find symbol. CHANGELOG.md:888-890 tells such callers to switch toSpringGeneratorSupport, but the break is not in the "Four diffs to expect when you upgrade" list, and the round 3 decision on the sibling case said "no source break in a minor release". This is not from the latest fix round; the original change introduced it and round 3 closed only theAutoSetSupportsibling. Unlike that case,@Deprecatedforwarders on these two classes create no back-edge: both are ejectable generators that already importSpringGeneratorSupport, and a forwarder to the support class is not a generator-to-generator reference. The remedy needs a decision, not the defect: either add@Deprecatedforwarders with the 1.0.13 signatures on both classes, or accept the break and list it under the upgrade diffs. If one of the older decisions omitted from my history already accepted this break, disregard.🔧 Fix applied.
1 info still open:
server/java/codegen-spring/src/test/java/com/metaobjects/generator/spring/OwnedPathNeverReachesPackagedSupportTest.java:92- Test gap opened by fix round 2 (the restored forwarders); no defect in the current code.noPackagedClassAnOwnedGeneratorReachesRefersBackToTheSupportClassflags a reached packaged class only when it refers DIRECTLY toSpringGeneratorSupport(line 89, 92-94). It puts the packaged ejectable generators in theownedset (line 76-77), so a reference to one of them is never a back-edge. Before round 2 that was safe: the helpers were gone fromSpringDtoGeneratorandSpringRepositoryGenerator, so no packaged class could call them. Round 2 restored 19@Deprecatedstatic forwarders on those two classes (SpringDtoGenerator.java:910-998, SpringRepositoryGenerator.java:477-499), each calling the packagedSpringGeneratorSupport. Plausible wrong behaviour the test now accepts: a packaged engine class an owned generator calls (TphPlan,SpringTypeMapper,AutoSetSupport,SpringM2mSupport,Fr019SharedEnum) callsSpringDtoGenerator.dtoComponentFields(entity). That compiles again, runs the packaged rule behind an owned generator, and the walk reports no back-edge. The sibling test at line 108 covers only generator-to-generator references, not engine-to-generator. I checked the source: today no packaged class outsideapidocsandGeneratorRegistryrefers to any ejectable generator, and neither of those is reached from an owned generator, so the invariant holds now. Fix: in the walk, also record a back-edge when a reached non-owned class refers to an ejectable generator class (ejectableGenerators().contains(outer(ref))). The check passes on the current tree.✅ **Test** - passed
✅ No issues found.
scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchainsscripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchains (baseline, already green)cd server/java && mvn -o -q -pl maven-plugin -am test -Dtest=EjectAloneRoundTripTest (6 tests, pass)cd server/java && mvn -o -q -pl codegen-spring test -Dtest=OwnedPathNeverReachesPackagedSupportTest,AutoSetSupportLegacyFormsTest (pass)cd server/java && mvn -o -q -pl codegen-kotlin test -Dtest=EjectedGeneratorAloneCompilesTest (pass)cd server/python && uv run --offline pytest -q tests/codegen/test_eject_independence.py tests/codegen/test_eject_runtime.py (13 passed, 2 skipped: fastapi missing)cd server/python && uv run --offline pytest -q --ignore=tests/integration (2829 passed, 2 skipped)cd server/java && mvn -o -q -pl maven-plugin,codegen-spring -am test (full regression, pass)✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.